local assets = {
    Asset("ANIM", "anim/twister_build.zip"),
    Asset("ANIM", "anim/twister_actions.zip"),
    Asset("ANIM", "anim/twister_basic.zip"),
    Asset("ANIM", "anim/twister_seal.zip"),
}

local brain = require("brains/walpurgisnightbrain")

local loots = {
    hivehat = 10,
    royal_jelly = 40,
    greengem = 40,
}

local sharedloot = {}
for loot, num in pairs(loots) do
    for i = 1, num do
        table.insert(sharedloot, {loot, 1.00})
    end
end

SetSharedLootTable("walpurgisnight", sharedloot)

local function CalcSanityAura(inst, observer)
    if inst.components.combat.target then
        return -TUNING.SANITYAURA_HUGE
    end

    return -TUNING.SANITYAURA_LARGE
end

local function DeltaModifier(inst, amount, overtime, cause, ignore_invincible, afflicter, ignore_absorb)
    if TheSim:FindFirstEntityWithTag("walpurgisnight_friend") then
        amount = amount * 0.6
    end
    return amount
end

local TARGET_DIST = 20
local MUST_TAGS = { "_combat" }
local CANT_TAGS = { "witch", "witchfriend" }
local function RetargetFn(inst)
    return FindEntity(inst, TARGET_DIST, function(guy)
        return inst.components.combat:CanTarget(guy)
    end, MUST_TAGS, CANT_TAGS)
end

local function KeepTargetFn(inst, target)
    return inst.components.combat:CanTarget(target) and not target:HasOneOfTags(CANT_TAGS)
end

local friends = {
    "clownhorse",
    "clownrabbit",
    "magicalgirl_mami",
    "walpurgisnight_birchnutdrake",
}

local function OnTimerDone(inst, data)
    if not data then
        return
    end

    if data.name == "meteor" then
        if inst.components.combat.target then
            local meteor = SpawnPrefab("walpurgisnight_shadowmeteor")
            local x, y, z = inst.components.combat.target.Transform:GetWorldPosition()
            meteor.Transform:SetPosition(x, y, z)

            inst.components.timer:StartTimer("meteor", TUNING.WALPURGISNIGHT_METEOR_TIMEDONE)
        else
            inst.components.timer:StartTimer("meteor", 1)
        end
    elseif data.name == "summon" then

        for i = 1, 30 do
            local x, y, z = inst.Transform:GetWorldPosition()

            local s = i / 32
            local a = math.sqrt(s * 512)
            local b = math.sqrt(s) * 11
            local pos = Vector3(x + math.sin(a) * b, 0, z + math.cos(a) * b)

            local friend = friends[math.random(1, #friends)]
            local guy = SpawnAt(friend, pos)
            if guy.components.combat then
                guy.components.combat:SuggestTarget(inst.components.combat.target)
            end
        end

        inst.components.timer:StartTimer("summon", TUNING.WALPURGISNIGHT_METEOR_TIMEDONE)
    end
end

local function fn()
    local inst = CreateEntity()
	inst.entity:AddTransform()
	inst.entity:AddAnimState()
    inst.entity:AddSoundEmitter()
	inst.entity:AddDynamicShadow()
    inst.entity:AddPhysics()
    inst.entity:AddNetwork()

    inst.Transform:SetFourFaced()
    inst.DynamicShadow:SetSize(6, 3.5)

    inst.Physics:SetMass(1000)
    inst.Physics:SetCapsule(1.5, 1)
    inst.Physics:SetFriction(0)
    inst.Physics:SetDamping(5)
    inst.Physics:SetCollisionGroup(COLLISION.CHARACTERS)
    inst.Physics:ClearCollisionMask()
    inst.Physics:CollidesWith((TheWorld.has_ocean and COLLISION.GROUND) or COLLISION.WORLD)
    inst.Physics:CollidesWith(COLLISION.CHARACTERS)

    inst.AnimState:SetBank("twister")
    inst.AnimState:SetBuild("twister_build")
    inst.AnimState:PlayAnimation("idle_loop", true)
    inst.AnimState:Hide("twister_water_fx")

	inst:AddTag("epic")
    inst:AddTag("monster")
    inst:AddTag("hostile")
    inst:AddTag("walpurgisnight")
    inst:AddTag("scarytoprey")
    inst:AddTag("largecreature")
    inst:AddTag("soulless")
    inst:AddTag("poisonimmune")
    inst:AddTag("witch")
    inst:AddTag("ignorewalkableplatforms")

    inst.entity:SetCanSleep(false)

    inst.entity:SetPristine()

    if not TheWorld.ismastersim then
        return inst
    end

    inst.SoundEmitter:PlaySound("witch_night_prologue/music/prologue", "witch_night_prologue")

    inst:AddComponent("inspectable")

    inst:AddComponent("inventory")

    inst:AddComponent("timer")
    inst.components.timer:StartTimer("meteor", 10)
    inst.components.timer:StartTimer("summon", 1)

    inst:AddComponent("sanityaura")
    inst.components.sanityaura.aurafn = CalcSanityAura

    inst:AddComponent("health")
    inst.components.health:SetMaxHealth(TUNING.WALPURGISNIGHT_HEALTH)
    inst.components.health.destroytime = 5
    inst.components.health.deltamodifierfn = DeltaModifier

    inst:AddComponent("combat")
    inst.components.combat:SetDefaultDamage(TUNING.WALPURGISNIGHT_DAMAGE)
    inst.components.combat.playerdamagepercent = TUNING.WALPURGISNIGHT_DAMAGE_PLAYER_PERCENT
    inst.components.combat:SetRange(TUNING.WALPURGISNIGHT_ATTACK_RANGE, TUNING.WALPURGISNIGHT_MELEE_RANGE)
    inst.components.combat:SetAreaDamage(TUNING.WALPURGISNIGHT_MELEE_RANGE, 0.8)
    inst.components.combat:SetAttackPeriod(TUNING.WALPURGISNIGHT_ATTACK_PERIOD)
    inst.components.combat:SetRetargetFunction(3, RetargetFn)
    inst.components.combat:SetKeepTargetFunction(KeepTargetFn)

    local _DoAreaAttack = inst.components.combat.DoAreaAttack
    inst.components.combat.DoAreaAttack = function(self, target, range, weapon, validfn, stimuli, excludetags)
        excludetags = excludetags or {}
        table.insert(excludetags, "witchfriend")
        table.insert(excludetags, "witchfriend")

        return _DoAreaAttack(self, target, range, weapon, validfn, stimuli, excludetags)
    end

    inst:AddComponent("lootdropper")
    inst.components.lootdropper:SetChanceLootTable("walpurgisnight")

    inst:AddComponent("locomotor")
    inst.components.locomotor.walkspeed = TUNING.WALPURGISNIGHT_CALM_WALK_SPEED
    inst.components.locomotor.runspeed = TUNING.WALPURGISNIGHT_ANGRY_WALK_SPEED
    inst.components.locomotor.pathcaps = { allowocean = true }
    inst.components.locomotor:SetShouldRun(true)

    inst:AddComponent("knownlocations")

    inst:SetStateGraph("SGwalpurgisnight")
    inst:SetBrain(brain)

    inst:ListenForEvent("timerdone", OnTimerDone)

    inst.OnRemoveEntity = function(inst)
        inst.SoundEmitter:KillSound("witch_night_prologue")
    end

    return inst
end

return Prefab("walpurgisnight", fn, assets)
